use std::{
    collections::HashMap,
    fs::File,
    io::{self, BufRead, BufReader},
};

#[derive(Clone, Debug, Default)]
struct Converter {
    s_dict: HashMap<char, char>,
    r_dict: HashMap<String, String>,
}

impl Converter {
    fn new(s_file: &str, r_file: &str) -> io::Result<Self> {
        let mut ret = Converter::default();
        ret.load_file(s_file, true)?;
        ret.load_file(r_file, false)?;
        Ok(ret)
    }

    fn init_s(&mut self, k: &str, v: &str) {
        self.s_dict
            .insert(k.chars().next().unwrap(), v.chars().next().unwrap());
    }

    fn init_r(&mut self, k: &str, v: &str) {
        self.r_dict.insert(k.to_string(), v.to_string());
    }

    fn load_file(&mut self, file_name: &str, is_s: bool) -> io::Result<()> {
        let file = File::open(file_name)?;
        let mut reader = BufReader::new(file);
        let mut data = String::new();
        loop {
            data.clear();
            let bytes = reader.read_line(&mut data)?;
            if bytes == 0 {
                break;
            }
            if let Some((k, v)) = data.trim().split_once(',') {
                if is_s {
                    self.init_s(k, v);
                } else {
                    self.init_r(k, v);
                }
            }
        }
        Ok(())
    }

    fn convert(&self, input: &str) -> String {
        let mut ret = String::new();

        for c in input.chars() {
            ret.push(*self.s_dict.get(&c).unwrap_or(&c));
        }

        for (k, v) in &self.r_dict {
            if ret.contains(k) {
                ret = ret.replace(k, v);
            }
        }

        ret
    }
}

pub fn converter(input: &str, tp: &str) -> String {
    let c = Converter::new(&format!("s_{tp}.data"), &format!("r_{tp}.data")).unwrap();
    c.convert(input)
}
